<script setup lang="ts">
import { onMounted, ref } from 'vue'
import {
  initDemo,
  setCtTransferFunctionForVolumeActor,
  setPetTransferFunctionForVolumeActor,
  createImageIdsAndCacheMetaData
} from '@/helpers'
import {
  cache, Enums, RenderingEngine, setVolumesForViewports, Types, volumeLoader
} from '@cornerstonejs/core'

const { ViewportType, RequestType } = Enums
const MAX_NUM_TIMEPOINTS = 40
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { NButton, NInput } from 'naive-ui'

const {
  PanTool,
  ZoomTool,
  StackScrollMouseWheelTool,
  CrosshairsTool,
  ToolGroupManager,
  Enums: csToolsEnums,
  utilities: csToolsUtilities
} = cornerstoneTools
const { MouseBindings } = csToolsEnums
onMounted(async () => {
  await initDemo()
  cache.setMaxCacheSize(4 * 1024 * 1024 * 1024)
})

function createToolGroups() {
  const mprToolGroupId = 'mprToolGroupId'
  const obliqueToolGroupId = 'obliqueToolGroupId'
  const mprToolGroup = ToolGroupManager.createToolGroup(mprToolGroupId)
  const obliqueToolGroup = ToolGroupManager.createToolGroup(obliqueToolGroupId)

  // Set the tool group on the viewport. Add only the first three viewports
  // because crosshairs can work with up to three viewports
  viewportIds.slice(0, 3).forEach((viewportId, i) => {
    mprToolGroup.addViewport(viewportId, renderingEngineId)
  })

  obliqueToolGroup.addViewport(viewportIds[3], renderingEngineId)

  return { mprToolGroup, obliqueToolGroup }
}

let renderingEngine

function initViewports(volume) {
  // Instantiate a rendering engine
  renderingEngine = new RenderingEngine(renderingEngineId)
  const { volumeId } = volume

  const viewportInputArray = [
    {
      viewportId: viewportIds[0],
      type: ViewportType.ORTHOGRAPHIC,
      element: axRef.value![0],
      defaultOptions: {
        background: <Types.Point3>[0.2, 0, 0.2]
      }
    },
    {
      viewportId: viewportIds[1],
      type: ViewportType.ORTHOGRAPHIC,
      element: sagRef.value![0],
      defaultOptions: {
        orientation: Enums.OrientationAxis.CORONAL,
        background: <Types.Point3>[0.2, 0, 0.2]
      }
    },
    {
      viewportId: viewportIds[2],
      type: ViewportType.ORTHOGRAPHIC,
      element: corRef.value![0],
      defaultOptions: {
        orientation: Enums.OrientationAxis.SAGITTAL,
        background: <Types.Point3>[0.2, 0, 0.2]
      }
    },
    {
      viewportId: viewportIds[3],
      type: ViewportType.ORTHOGRAPHIC,
      element: obliqueRef.value![0],
      defaultOptions: {
        orientation: {
          // Random oblique orientation
          viewUp: <Types.Point3>[
            -0.5962687530844388, 0.5453181550345819, -0.5891448751239446
          ],
          viewPlaneNormal: <Types.Point3>[
            -0.5962687530844388, 0.5453181550345819, -0.5891448751239446
          ]
        },
        background: <Types.Point3>[0.2, 0, 0.2]
      }
    }
  ]

  renderingEngine.setViewports(viewportInputArray)

  // Set volumes on the viewports
  setVolumesForViewports(
    renderingEngine,
    [{ volumeId, callback: setPetTransferFunctionForVolumeActor }],
    viewportIds
  )


  return viewportIds
}

async function createVolume(numTimePoints: number): any {
  const { metaDataManager } = cornerstoneDICOMImageLoader.wadors

  if (numTimePoints < 1 || numTimePoints > MAX_NUM_TIMEPOINTS) {
    throw new Error('numTimePoints is out of range')
  }
  const params = {
    StudyInstanceUID:
      '1.3.6.1.4.1.12842.1.1.14.3.20220915.105557.468.2963630849',
    SeriesInstanceUID:
      '1.3.6.1.4.1.12842.1.1.22.4.20220915.124758.560.4125514885',
    wadoRsRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
  }
  // let imageIds: string[] = []
  // const seriesIds = [
  //   // '1.2.392.200036.9107.307.31909.120240301.1102826.142329',
  //   // '1.2.2046.7929.09.1.20240301.103311.10920',
  //   // '1.2.2046.7929.09.1.20240301.103359.25746',
  //   // '1.2.2046.7929.09.1.20240301.103447.93095',
  //   // '1.2.2046.7929.09.1.20240301.103535.17768',
  //   // '1.2.2046.7929.09.1.20240301.103624.79468',
  //   // '1.2.2046.7929.09.1.20240301.103712.23891',
  //   // '1.2.2046.7929.09.1.20240301.103800.93438',
  //   '1.2.2046.7929.09.1.20240301.103848.91571',
  //   '1.2.2046.7929.09.1.20240301.103937.38151'
  // ]
  // for (let i = 0; i < seriesIds.length; i++) {
  //   const params = {
  //     StudyInstanceUID:
  //       '1.2.392.200036.9107.307.31909.120240301.1102826.123575',
  //     SeriesInstanceUID: seriesIds[i],
  //     wadoRsRoot: '/dicom-web'
  //   }
  //   let ids = await createImageIdsAndCacheMetaData(params)
  //   imageIds = [...imageIds, ...ids]
  // }

  const NUM_IMAGES_PER_TIME_POINT = 235
  const TOTAL_NUM_IMAGES = MAX_NUM_TIMEPOINTS * NUM_IMAGES_PER_TIME_POINT
  // 5 * 235
  const numImagesToLoad = numTimePoints * NUM_IMAGES_PER_TIME_POINT

  const firstInstanceNumber = TOTAL_NUM_IMAGES - numImagesToLoad + 1
  let imageIds = await createImageIdsAndCacheMetaData(params)
  imageIds = imageIds.filter((imageId) => {
    const instanceMetaData = metaDataManager.get(imageId)
    const instanceTag = instanceMetaData['00200013']
    const instanceNumber = parseInt(instanceTag.Value[0])

    return instanceNumber >= firstInstanceNumber
  })

  // Define a unique id for the volume
  const volumeLoaderScheme = 'cornerstoneStreamingDynamicImageVolume' // Loader id which defines which volume loader to use
  const volumeName = 'PT_VOLUME_ID' // Id of the volume less loader prefix
  const volumeId = `${volumeLoaderScheme}:${volumeName}` // VolumeId with loader id + volume id

  // Define a volume in memory
  const volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds
  })
  return volume
}

const volumeName = 'CT_VOLUME_ID' // Id of the volume less loader prefix
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume' // Loader id which defines which volume loader to use
const volumeId = `${volumeLoaderScheme}:${volumeName}` // VolumeId with loader id + volume id
const sagRef = ref(null)
const axRef = ref(null)
const corRef = ref(null)
const obliqueRef = ref(null)
const viewportId1 = 'Axial'
const viewportId2 = 'Sagittal'
const viewportId3 = 'Coronal'
const viewportId4 = 'oblique'
const viewportIds = [viewportId1, viewportId2, viewportId3, viewportId4]
const renderingEngineId = 'renderingEngineId'
const views = [
  {
    'ref': axRef,
    'class': 'lt',
    'viewportId': viewportId1
  },
  {
    'ref': sagRef,
    'class': 'lb',
    'viewportId': viewportId2
  },
  {
    'ref': corRef,
    'class': 'rt',
    'viewportId': viewportId3
  },
  {
    'ref': obliqueRef,
    'class': '',
    'viewportId': viewportId4
  }
]

const viewportColors = {
  [viewportIds[0]]: 'rgb(200, 0, 0)',
  [viewportIds[1]]: 'rgb(200, 200, 0)',
  [viewportIds[2]]: 'rgb(0, 200, 0)'
}

const viewportReferenceLineControllable = viewportIds.slice()
const viewportReferenceLineDraggableRotatable = viewportIds.slice()
const viewportReferenceLineSlabThicknessControlsOn = viewportIds.slice()

function getReferenceLineColor(viewportId) {
  return viewportColors[viewportId]
}

function getReferenceLineControllable(viewportId) {
  return viewportReferenceLineControllable.includes(viewportId)
}

function getReferenceLineDraggableRotatable(viewportId) {
  return viewportReferenceLineDraggableRotatable.includes(viewportId)
}

function getReferenceLineSlabThicknessControlsOn(viewportId) {
  return viewportReferenceLineSlabThicknessControlsOn.includes(viewportId)
}


function initCrosshairsTool(toolGroup) {

  toolGroup.addTool(CrosshairsTool.toolName, {
    getReferenceLineColor,
    getReferenceLineControllable,
    getReferenceLineDraggableRotatable,
    getReferenceLineSlabThicknessControlsOn
  })

  toolGroup.setToolActive(CrosshairsTool.toolName, {
    bindings: [{ mouseButton: MouseBindings.Primary }]
  })
}

function initTools(toolGroup, options?) {
  // Add the tools to the tool group
  toolGroup.addTool(PanTool.toolName)
  toolGroup.addTool(ZoomTool.toolName)
  toolGroup.addTool(StackScrollMouseWheelTool.toolName)

  toolGroup.setToolActive(PanTool.toolName, {
    bindings: [{ mouseButton: MouseBindings.Auxiliary }]
  })

  toolGroup.setToolActive(ZoomTool.toolName, {
    bindings: [{ mouseButton: MouseBindings.Secondary }]
  })

  toolGroup.setToolActive(StackScrollMouseWheelTool.toolName)

  if ((options ?? {}).initCrosshairsTool === true) {
    initCrosshairsTool(toolGroup)
  }

  return toolGroup
}

const activeViewportIdRef = ref(viewportId1)
const loadTime = ref(5)
const play = () => {

  csToolsUtilities.cine.playClip(axRef.value[0], {
    framesPerSecond: 24,
    dynamicCineEnabled: true
  })
}
const pause = () => {
  csToolsUtilities.cine.stopClip(axRef.value[0])
}
const load = async () => {
  const volume = await createVolume(loadTime.value)
  initViewports(volume)
  const { mprToolGroup, obliqueToolGroup } = createToolGroups()

  initTools(mprToolGroup, { initCrosshairsTool: true })
  initTools(obliqueToolGroup)
  volume.load()
  // Render the image
  renderingEngine.renderViewports(viewportIds)
}
</script>

<template>
  <div class="w-full max-w-[900px] ml-auto mr-auto h-[500px] grid grid-cols-2 grid-rows-2 border-2 border-amber-200">
    <template v-for="view in views" :key="view.class">
      <div
        :class="[view.class, activeViewportIdRef === view.viewportId ? ' border-amber-500': 'border-transparent']"
        @click="activeViewportIdRef === view.viewportId"
        :ref="view.ref">
      </div>
    </template>
  </div>
  <n-input v-model:value="loadTime" />
  <n-button @click="load">load</n-button>
  <n-button @click="play">play</n-button>
  <n-button @click="pause">pause</n-button>
</template>

<style scoped>

</style>
